﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

using Nop.Core.Data;
using Nop.Core.Domain.Catalog;
using Nop.Core.Domain.Configuration;
using Nop.Core.Domain.Media;
using Nop.Core.Domain.Orders;
using Nop.Core.Domain.Payments;
using Nop.Core.Infrastructure;
using Nop.Services.Configuration;
using Nop.Services.Events;
using Nop.Services.Media;

using RonsHouse.Plugin.Misc.AlternativeStorage;

namespace RonsHouse.Plugin.Misc.AlternativeStorage.Services
{
	public class AlternativeStorageDownloadService : IDownloadService
	{
		#region Fields

        private readonly IRepository<Download> _downloadRepository;
        private readonly IEventPublisher _eventPublisher;
		private readonly ISettingService _settingService;

        #endregion

        #region Ctor

		//public AlternativeStorageDownloadService()
		//{
		//	this._downloadRepository = EngineContext.Current.Resolve<IRepository<Download>>();
		//	this._eventPubisher = EngineContext.Current.Resolve<IEventPublisher>();
		//	this._settingService = EngineContext.Current.Resolve<ISettingService>();
		//}

		public AlternativeStorageDownloadService(IRepository<Download> downloadRepository,
            IEventPublisher eventPubisher, ISettingService settingService)
        {
            this._downloadRepository = downloadRepository;
            this._eventPublisher = eventPubisher;
			this._settingService = settingService;
        }

        #endregion

		public Download GetDownloadById(int downloadId)
		{
			if (downloadId == 0)
				return null;

			Download download = _downloadRepository.GetById(downloadId);
			
			if (!download.UseDownloadUrl)
			{
				var settings = _settingService.LoadSetting<AlternativeStorageSettings>();
				if (!String.IsNullOrEmpty(settings.FileSystemPicturePath))
				{
					var storageProviderService = new FileSystemStorageProvider();
					download.DownloadBinary = storageProviderService.Get(download);
				}
			}

			return download;
		}

		public Download GetDownloadByGuid(Guid downloadGuid)
		{
			if (downloadGuid == Guid.Empty)
				return null;

			var query = from o in _downloadRepository.Table
						where o.DownloadGuid == downloadGuid
						select o;
			var download = query.FirstOrDefault();

			if (!download.UseDownloadUrl)
			{ 
				var settings = _settingService.LoadSetting<AlternativeStorageSettings>();
				if (!String.IsNullOrEmpty(settings.FileSystemPicturePath))
				{
					var storageProviderService = new FileSystemStorageProvider();
					download.DownloadBinary = storageProviderService.Get(download);
				}
			}

			return download;
		}

		public void DeleteDownload(Download download)
		{
			if (download == null)
				throw new ArgumentNullException("download");

			if (!download.UseDownloadUrl)
			{ 
				var settings = _settingService.LoadSetting<AlternativeStorageSettings>();
				if (!String.IsNullOrEmpty(settings.FileSystemPicturePath))
				{
					var storageProviderService = new FileSystemStorageProvider();
					storageProviderService.Delete(download);
				}
			}

			_downloadRepository.Delete(download);

			_eventPublisher.EntityDeleted(download);
		}

		public void InsertDownload(Download download)
		{
			if (download == null)
				throw new ArgumentNullException("download");

			if (!download.UseDownloadUrl)
			{ 
				var settings = _settingService.LoadSetting<AlternativeStorageSettings>();
				if (!String.IsNullOrEmpty(settings.FileSystemPicturePath))
				{
					var data = download.DownloadBinary;
					download.DownloadBinary = new byte[0];

					//save to database first, so an ID comes back
					_downloadRepository.Insert(download);

					var storageProviderService = new FileSystemStorageProvider();
					storageProviderService.Save(download, data);
				}
			}
			else
			{
				_downloadRepository.Insert(download);
			}

			_eventPublisher.EntityInserted(download);
		}

		public void UpdateDownload(Download download)
		{
			if (download == null)
				throw new ArgumentNullException("download");

			if (!download.UseDownloadUrl)
			{
				var settings = _settingService.LoadSetting<AlternativeStorageSettings>();
				if (!String.IsNullOrEmpty(settings.FileSystemPicturePath))
				{
					var data = download.DownloadBinary;
					download.DownloadBinary = new byte[0];

					var storageProviderService = new FileSystemStorageProvider();
					storageProviderService.Save(download, data);
				}
			}
			
			_downloadRepository.Update(download);
			
			_eventPublisher.EntityUpdated(download);
		}

		#region Untouched methods, copied from core
		
		public bool IsDownloadAllowed(OrderItem orderItem)
		{
			if (orderItem == null)
				return false;

			var order = orderItem.Order;
			if (order == null || order.Deleted)
				return false;

			//order status
			if (order.OrderStatus == OrderStatus.Cancelled)
				return false;

			var product = orderItem.Product;
			if (product == null || !product.IsDownload)
				return false;

			//payment status
			switch (product.DownloadActivationType)
			{
				case DownloadActivationType.WhenOrderIsPaid:
					{
						if (order.PaymentStatus == PaymentStatus.Paid && order.PaidDateUtc.HasValue)
						{
							//expiration date
							if (product.DownloadExpirationDays.HasValue)
							{
								if (order.PaidDateUtc.Value.AddDays(product.DownloadExpirationDays.Value) > DateTime.UtcNow)
								{
									return true;
								}
							}
							else
							{
								return true;
							}
						}
					}
					break;
				case DownloadActivationType.Manually:
					{
						if (orderItem.IsDownloadActivated)
						{
							//expiration date
							if (product.DownloadExpirationDays.HasValue)
							{
								if (order.CreatedOnUtc.AddDays(product.DownloadExpirationDays.Value) > DateTime.UtcNow)
								{
									return true;
								}
							}
							else
							{
								return true;
							}
						}
					}
					break;
				default:
					break;
			}

			return false;
		}

		public bool IsLicenseDownloadAllowed(OrderItem orderItem)
		{
			if (orderItem == null)
				return false;

			return IsDownloadAllowed(orderItem) &&
				orderItem.LicenseDownloadId.HasValue &&
				orderItem.LicenseDownloadId > 0;
		}
		
		#endregion
	}
}
